#include<iostream>
#include<Eigen/Dense>
#include<algorithm>
#include<fstream>
#include<vector>
#include<string>
#include<cmath>
struct DataPoint {
    double x, y;
};
void genData(const std::string& filename, int funcType, double a, double b, double c, double d);//调用数据生成函数

Eigen::VectorXd leastSquares(const std::string& filename, int funcType);//调用用最小二乘法处理数据的函数

void read_data(const std::string& filename, std::vector<DataPoint>& data);//读入数据
double predict(double x, const std::vector<double>& params, int t);//计算预测值
void gradient_descent(const std::vector<DataPoint>& data, std::vector<double>& params, int t, double learning_rate = 0.01, int iterations = 1000);//计算梯度下降的损失函数和梯度
double compute_residual_sum(const std::vector<DataPoint>& data, const std::vector<double>& params, int t);//计算残差平方和（拟合度）

void printOpenFile(std::string& filename)//打印文件中的内容，检验数据生成情况
{
    std::ifstream inFile(filename);
    if (!inFile)
    {
        std::cout << "open error:" << filename << std::endl;
        return;
    }
    double x, y;
    while (inFile >> x >> y)
    {
        std::cout << "x=" << x << " " << "y=" << y << std::endl;
    }
    inFile.close();
}
int main()
{
    int funcType;
    double a, b, c=0, d=0;
    std::string filename = "some.dat";
    char choice;
    std::cout << "Enter the function you wanna choose,l stand for leastSquares,while m stands for gradient_descent: ";
    std::cin >> choice;
    std::cout << "Enter function type,especially,1 for linear,2 for quadratic,3 for cubic:";
    std::cin >> funcType;//选择函数形式

        switch (funcType)//执行对应函数
        {
        case(1):
            std::cout << "Enter parameters a and b for the linear function y=ax+b:";
            std::cin >> a >> b;
            break;
        case(2):
            std::cout << "Enter parameters a、b and c for the quadratic fuction y=ax^2+bx+c:";
            std::cin >> a >> b >> c;
            break;
        case(3):
            std::cout << "Enter parameters a、b、c and d for the cubic function y=ax^3+bx^2+cx+d:";
            std::cin >> a >> b >> c >> d;
            break;
        default:
            std::cout << "Excuse me but a invalid Type";
            return -1;
        }
        genData(filename, funcType, a, b, c, d);//生成数据
    if (choice == 'l')
    {
        std::cout << "Data set has been generated and saved to" << filename << std::endl;//提示保存数据成功
        printOpenFile(filename);//打印数据
        std::cout << std::endl << leastSquares(filename, funcType);//使用最小二乘法拟合，并输出函数各次项系数
    }
    else if (choice == 'm')
    {
        std::vector<DataPoint>data;
        read_data(filename, data);
        std::cout << "Enter function type,especially,1 for linear,2 for quadratic,3 for cubic:";
        int choice2;
        std::cin >> choice2;
        std::vector<double>param(choice2 == 1 ? 2 : (choice==2 ? 3 : 4), 0.0);
        gradient_descent(data, param,choice2);//计算梯度下降的损失函数和梯度
        std::cout << "Fitted parameters:";
        for (double p : param)
            std::cout << p << " ";//输出拟合后的参数
        std::cout << std::endl;
        double residual_sum = compute_residual_sum(data, param, choice2);//计算残差平方和（即拟合度）
        std::cout << "Residual Sum of Squares: " << residual_sum << std::endl;
        printOpenFile(filename);//打印数据
    }
    return 0;
}